#ifndef __LAYERMANAGER_H__
#define __LAYERMANAGER_H__

#include <stdlib.h>
#include <string.h>
//#include <math.h>
#include <RenderLibServer.h>

//using namespace Elastos;

#define MaxNumLayer        128

#define A8         1
#define RGB24      2
#define ARGB32     3

inline int max(int a, int b)
{
    return a>=b ? a:b;
}

inline int min(int a, int b)
{
    return a<=b ? a:b;
}

typedef struct TagRENDERSTRUCT
{
public:
    int Width;
    int Height;
    int SrcX;
    int SrcY;
    int DstX;
    int DstY;
    int AlphaValue;
    int RenderMethod;
} RENDERSTRUCT;

typedef struct TagRENDERSTRUCTEX : public RENDERSTRUCT
{
public:
    int StretchWidth;
    int StretchHeight;
} RENDERSTRUCTEX;

typedef struct tagStretchInfo
{
    int   Width;
    int   Height;
    int   OffsetX;
    int   OffsetY;
}STRETCHINFO;

struct Layer
{
    Layer *                 pPrevLayer;
    Layer *                 pNextLayer;
    BitmapBufInfo               Image;
    BitmapBufInfo               SrcImage;
    Point                   Position;
    STRETCHINFO             StretchInfo;
    int                     Transparency;
    bool                    Visible;
    bool                    bZoom;
    bool                    bTransform;
    unsigned short          Index;
    unsigned short          uRenderMethod;
};

class LayerManager
{
public:
    LayerManager(int width, int height);
    ~LayerManager();

    int LayerBringForward(int index);
    int LayerSendBackward(int index);
    int LayerBringToFront(int index);
    int LayerSendToBack(int index);

    void LayerRestore(int index);
    void LayerFlip(int index, int direction);
    int RemoveLayerByIndex(int index);
    void RemoveAllLayers();
    int AddLayer(BitmapBufInfo & img, int x = 0, int y = 0, int level = 255);
    int DuplicateLayer(int index, int xin, int yin, int level, int style);
    int GetAllLayerIds(int* pid);
    int GetNumberOfLayers();

    void RenderToBuffer(BitmapBufInfo & img, int OffsetX, int OffsetY,
                        int RenderLen,
                        int RenderHt);

    int LayerResize(int index, int width, int height);
    int LayerRotate90(int index, int times);

    inline void SetLayerTransparency(int index, int level)
    {
        m_pLayer[index]->Transparency = level;
    }

    inline int GetLayerTransparency(int index)
    {
        return m_pLayer[index]->Transparency;
    }


    inline void ShowLayer(int index, bool visible)
    {
        m_pLayer[index]->Visible = visible;
    }

    inline void MoveLayer(int index, int x, int y)
    {
        m_pLayer[index]->Position.x += x;
        m_pLayer[index]->Position.y += y;
    }

    inline void SetLayerPosition(int index, int x, int y)
    {
        m_pLayer[index]->Position.x = x;
        m_pLayer[index]->Position.y = y;
    }

    inline void SetLayerBlendType(int index, int type)
    {
        m_pLayer[index]->uRenderMethod = (unsigned short)type;
    }

    inline void SetLayerColor(int index, unsigned char R, unsigned char G, unsigned char B)
    {
        unsigned int flag = m_pLayer[index]->Image.pixelFormat & 3;
        unsigned int temp = 0;

        temp |= R<<24;
        temp |= G<<16;
        temp |= B<<8;

        m_pLayer[index]->Image.pixelFormat = temp | flag;
    }

    inline int GetLayerType(int index)
    {
        return m_pLayer[index]->SrcImage.pixelFormat & 3;
    }

    inline void SetBackgroundColor(unsigned char R, unsigned char G, unsigned char B)
    {
        m_nBackgroundColor = B | (G<<8) | (R<<16);
    }

    inline Point * GetLayerPosition(int index)
    {
        return &(m_pLayer[index]->Position);
    }

    inline BitmapBufInfo * GetLayerBits(int index)
    {
        return &(m_pLayer[index]->Image);
    }

    inline Layer * GetLayerInfo(int index)
    {
        return m_pLayer[index];
    }


    inline BitmapBufInfo * GetSrcLayerBits(int index)
    {
        return &(m_pLayer[index]->SrcImage);
    }

    inline void StretchLayer(int index, int StretchX, int StretchY)
    {
        if ((0 == StretchX) && (0 == StretchY)) {
            m_pLayer[index]->bZoom = false;
            m_pLayer[index]->StretchInfo.OffsetX = 0;
            m_pLayer[index]->StretchInfo.OffsetY = 0;
        }
        m_pLayer[index]->bZoom = true;
        m_pLayer[index]->StretchInfo.OffsetX = StretchX;
        m_pLayer[index]->StretchInfo.OffsetY = StretchY;

        m_pLayer[index]->StretchInfo.Width  = m_pLayer[index]->Image.width
                                              + (StretchX<<1);
        m_pLayer[index]->StretchInfo.Height = m_pLayer[index]->Image.height
                                              + (StretchY<<1);

        if (m_pLayer[index]->StretchInfo.Width < 2 || m_pLayer[index]->StretchInfo.Height < 2)
            m_pLayer[index]->Visible = false;
        else m_pLayer[index]->Visible = true;
    }

    inline void ResizeLayer(int index, int StretchX, int StretchY, int alignX, int alignY)
    {
        if ((m_pLayer[index]->Image.width == StretchX)
            && (m_pLayer[index]->Image.height == StretchY)) {
            m_pLayer[index]->bZoom = false;
            m_pLayer[index]->StretchInfo.OffsetX = 0;
            m_pLayer[index]->StretchInfo.OffsetY = 0;
        }

        m_pLayer[index]->bZoom = true;
        m_pLayer[index]->StretchInfo.OffsetX = (StretchX - m_pLayer[index]->Image.width)*(alignX&3)/2;
        m_pLayer[index]->StretchInfo.OffsetY = (StretchY - m_pLayer[index]->Image.height)*(alignY&3)/2;

        m_pLayer[index]->StretchInfo.Width  = StretchX;
        m_pLayer[index]->StretchInfo.Height = StretchY;

        if (m_pLayer[index]->StretchInfo.Width < 2 || m_pLayer[index]->StretchInfo.Height < 2)
            m_pLayer[index]->Visible = false;
        else m_pLayer[index]->Visible = true;
    }

    int WarpLayerLR(int index, int StretchX, int StretchYL, int StretchYR);
    int WarpLayerTD(int index, int StretchY, int StretchXT, int StretchXD);
    int ShearLayer(int index, int offset, int StretchX, int StretchY);
    int WaveLayer(int index, int* aSampleX16, int width, int height, int InnerWidth);
    int MergeLayer(int SrcIndex, int DstIndex);

    inline void SetViewPosition(int x, int y)
    {
        m_stViewRectPosition.x = x;
        m_stViewRectPosition.y = y;
    }

    inline void IsTransparent(bool flag)
    {
        m_bTransparent = flag;
    }

    inline void ZoomLayer(int index, float zoomlevel)
    {
        int x,y;
        x = int((m_pLayer[index]->Image.width>>1) * (zoomlevel - 1));
        y = int((m_pLayer[index]->Image.height>>1) * (zoomlevel - 1));
        StretchLayer(index, x, y);
    }

//    inline bool LayerHitTest(int index, Point position)
//    {
//        return ((m_pLayer[index]->Visible)
//            && ((m_pLayer[index]->Position.x
//                - m_pLayer[index]->StretchInfo.OffsetX)
//                <= (m_stViewRectPosition.x + position.x))
//            && ((m_pLayer[index]->Position.x
//                - m_pLayer[index]->StretchInfo.OffsetX
//                + m_pLayer[index]->StretchInfo.Width)
//                >= (m_stViewRectPosition.x + position.x))
//            && ((m_pLayer[index]->Position.y
//                - m_pLayer[index]->StretchInfo.OffsetY)
//                <= (m_stViewRectPosition.y + position.y))
//            && ((m_pLayer[index]->Position.y
//                - m_pLayer[index]->StretchInfo.OffsetY
//                + m_pLayer[index]->StretchInfo.Height)
//                >= (m_stViewRectPosition.y + position.y)));
//    }

    inline void ZoomLayerByPoint(int index, float zoomlevel, int x, int y)
    {
        int StretchX,StretchY;

        //if (!LayerHitTest(index, anchor)) return;

//        anchor.x = (m_stViewRectPosition.x
//                   + anchor.x - (m_pLayer[index]->Position.x
//                   - m_pLayer[index]->StretchInfo.OffsetX ))
//                   * m_pLayer[index]->SrcImage.width
//                   / m_pLayer[index]->StretchInfo.Width;
//        anchor.y = (m_stViewRectPosition.y
//                   + anchor.y - (m_pLayer[index]->Position.y
//                   - m_pLayer[index]->StretchInfo.OffsetY ))
//                   * m_pLayer[index]->SrcImage.height
//                   / m_pLayer[index]->StretchInfo.Height;
//
//        if ((anchor.x < 0) ||
//            (anchor.y < 0) ||
//            (anchor.x >= m_pLayer[index]->SrcImage.width) ||
//            (anchor.y >= m_pLayer[index]->SrcImage.height))
//            return;

        StretchX = int((m_pLayer[index]->SrcImage.width>>1) * (zoomlevel - 1));
        StretchY = int((m_pLayer[index]->SrcImage.height>>1) * (zoomlevel - 1));

        if ((0 == StretchX) && (0 == StretchY)) {
            m_pLayer[index]->bZoom = false;
            m_pLayer[index]->StretchInfo.OffsetX = 0;
            m_pLayer[index]->StretchInfo.OffsetY = 0;
        }
        m_pLayer[index]->bZoom = true;

        m_pLayer[index]->StretchInfo.OffsetX = (StretchX<<1) * x
                                           / m_pLayer[index]->SrcImage.width;
        m_pLayer[index]->StretchInfo.OffsetY = (StretchY<<1) * y
                                           / m_pLayer[index]->SrcImage.height;

        m_pLayer[index]->StretchInfo.Width  = m_pLayer[index]->SrcImage.width
                                              + (StretchX<<1);
        m_pLayer[index]->StretchInfo.Height = m_pLayer[index]->SrcImage.height
                                              + (StretchY<<1);

        if (m_pLayer[index]->StretchInfo.Width < 2)
            m_pLayer[index]->StretchInfo.Width = 2;
        if (m_pLayer[index]->StretchInfo.Height < 2)
            m_pLayer[index]->StretchInfo.Height = 2;
    }

    inline bool GetLayerVisibleRegion(int index, Region * reg)
    {
        reg->left = max(m_pLayer[index]->Position.x -  m_pLayer[index]->StretchInfo.OffsetX, 0);
        reg->top = max(m_pLayer[index]->Position.y -  m_pLayer[index]->StretchInfo.OffsetY, 0);
        reg->right = min(reg->left + m_pLayer[index]->StretchInfo.Width, m_nViewPlaneWidth);
        reg->bottom = min(reg->top + m_pLayer[index]->StretchInfo.Height,m_nViewPlaneHeight);

        if ((reg->left < reg->right) && (reg->top < reg->bottom)) return 1;
        else return 0;
    }



//    inline Point GetLayerBDPOS(int index)
//    {
//        int x,y;
//        x = int((m_pLayer[index]->Image.width>>1) * (zoomlevel - 1));
//        y = int((m_pLayer[index]->Image.height>>1) * (zoomlevel - 1));
//        StretchLayer(index, x, y);
//    }

    inline void SetScreenSize(int width, int height)
    {
        m_nViewPlaneWidth = width;
        m_nViewPlaneHeight = height;
    }

    int m_nViewPlaneWidth;
    int m_nViewPlaneHeight;

private:

    Layer *                 m_pLayer[MaxNumLayer];
    unsigned char           m_pLayerFlag[MaxNumLayer];
    int                     m_nNumberOfLayers;
    Layer *                 m_pTopLayer;
    Layer *                 m_pBottomLayer;
    int                     m_pAvailableSlot;
    //[Spirit/Particle][PixelAlpha][BlendOption]
//    BitmapBufInfo                   m_stTempBuffer;
    Point                   m_stViewRectPosition;
    unsigned int            m_nBackgroundColor;
    bool                    m_bTransparent;

    void RenderLayer(BitmapBufInfo & SrcImage,
                    BitmapBufInfo & DstImage,
                    RENDERSTRUCT & Renderstruct);

    void RenderStretchedLayer(BitmapBufInfo & SrcImage,
                    BitmapBufInfo & DstImage,
                    RENDERSTRUCTEX & Renderstruct);
};

#endif // __LAYERMANAGER_H__

